package cn.yeziji.forum.dao.impl;

import cn.yeziji.forum.annoataion.RemoveCache;
import cn.yeziji.forum.common.enums.ForumCommonStatus;
import cn.yeziji.forum.common.key.DetailsCacheKey;
import cn.yeziji.forum.converter.UserDetailConverter;
import cn.yeziji.forum.dao.base.ForumUserDetailBaseDao;
import cn.yeziji.forum.dao.intf.ForumUserDetailDao;
import cn.yeziji.forum.dao.iquery.UserDetailQuery;
import cn.yeziji.forum.dto.details.ForumUserOperaDetailDTO;
import cn.yeziji.forum.entity.ForumDetailsEntity;
import cn.yeziji.forum.entity.ForumUserDetailEntity;
import cn.yeziji.forum.exception.ForumException;
import cn.yeziji.forum.mapper.ForumDetailsMapper;
import cn.yeziji.forum.mapper.ForumUserDetailMapper;
import cn.yeziji.forum.utils.CacheUtils;
import cn.yeziji.forum.utils.JwtOperaUtils;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Objects;

/**
 * 用户操作文章
 *
 * @author gzkemays
 * @since 2021/12/21 15:54
 */
@Repository
public class ForumUserDetailDaoImpl extends ForumUserDetailBaseDao implements ForumUserDetailDao {
  @Resource ForumUserDetailMapper userDetailMapper;
  @Resource ForumDetailsMapper detailsMapper;
  @Resource HttpServletRequest request;
  @Resource CacheUtils cache;

  @Override
  // TODO: cache?
  @RemoveCache(
      value = DetailsCacheKey.CACHE_GET_DETAIL_KEY,
      joinery = "::",
      jsonKey = "detailId",
      blur = true)
  public String update(ForumUserOperaDetailDTO dto) {
    Integer userId = JwtOperaUtils.getUserIdByRequest(request);
    dto.setUserId(userId);
    ForumUserDetailEntity entity =
        userDetailMapper.findOne(
            UserDetailQuery.getDetailByDetailIdAndUserId(dto.getDetailId(), userId));
    // 首次操作
    if (Objects.isNull(entity)) {
      entity = UserDetailConverter.INSTANCE.dtoConvertToEntity(dto);
      userDetailMapper.insert(entity);
    } else {
      Boolean toCollection = dto.getToCollection();
      Boolean toGood = dto.getToGood();
      if (entity.getToCollection().equals(toCollection) || entity.getToGood().equals(toGood)) {
        // 这里如果用户操作了相同的操作，即：原本已经收藏了，但是又收藏，则跳出数据异常的问题。
        throw new ForumException(ForumCommonStatus.DATA_ERROR);
      }
      dto.setId(entity.getId());
      userDetailMapper.updateById(UserDetailConverter.INSTANCE.dtoConvertToEntity(dto));
    }
    return updateDetail(dto);
  }

  private String updateDetail(ForumUserOperaDetailDTO dto) {
    Integer userId = dto.getUserId();
    Integer detailId = dto.getDetailId();
    // 删除用户的文章缓存，其他用户则当缓存过期时，更新。
    cache.blurRemoveHash(DetailsCacheKey.CACHE_PAGE_HASH_KEY, "-(" + userId + ")");
    // 更新文章的操作数据
    ForumDetailsEntity detail = detailsMapper.findById(detailId);
    Integer collectionNumber = detail.getCollectionNumber();
    Integer goodNumber = detail.getGoodNumber();
    detail.setCollectionNumber(
        Objects.isNull(dto.getToCollection())
            ? collectionNumber
            : (dto.getToCollection() ? collectionNumber + 1 : collectionNumber - 1));
    detail.setGoodNumber(
        Objects.isNull(dto.getToGood())
            ? goodNumber
            : (dto.getToGood() ? goodNumber + 1 : goodNumber - 1));
    // 计算平均分
    if (dto.getToRate() != null) {
      // FIXME：此处是进行了重新计算
      List<BigDecimal> entities =
          userDetailMapper.listObjs(
              super.query().select.toRate().end().where.detailId().eq(detailId).end());
      // divide (decimal, scale, mode) 解决 Non-terminating decimal expansion; no exact representable decimal result. 的问题
      BigDecimal reduce =
          entities.stream()
              .reduce(BigDecimal.ZERO, BigDecimal::add)
              .divide(new BigDecimal(entities.size()), 2, RoundingMode.HALF_UP);
      String reduceStr = reduce.toString();
      detail.setAveRate(reduceStr);
      detailsMapper.updateById(detail);
      return reduceStr;
    }
    detailsMapper.updateById(detail);
    return "ok";
  }
}
